﻿using System.Text.RegularExpressions;
using wwl.Contract.Interfaces.Security;

namespace wwl.Infrastructure.Security.Hashing
{
  /// <summary>
  /// BCrypt密码哈希实现
  /// 使用业界标准的BCrypt算法，提供安全的密码存储和验证
  /// 实现契约层定义的 IHasher 接口
  /// </summary>
  public class BcryptHasher : IHasher
  {
    private readonly int _workFactor;

    /// <summary>
    /// 初始化BCrypt哈希器
    /// </summary>
    /// <param name="workFactor">
    /// 工作因子（成本因子），范围4-31，默认12
    /// 每增加1，哈希时间翻倍，安全性更高
    /// </param>
    public BcryptHasher(int workFactor = 12)
    {
      // 验证工作因子在合理范围内
      if (workFactor < 4 || workFactor > 31)
        throw new ArgumentException("工作因子必须在4-31之间", nameof(workFactor));

      _workFactor = workFactor;
    }

    /// <summary>
    /// 对明文密码进行BCrypt哈希处理
    /// </summary>
    public string HashPassword(string password)
    {
      if (string.IsNullOrWhiteSpace(password))
        throw new ArgumentException("密码不能为空", nameof(password));

      // 使用BCrypt算法生成带盐的哈希值
      return BCrypt.Net.BCrypt.HashPassword(password, _workFactor);
    }

    /// <summary>
    /// 验证密码是否与BCrypt哈希值匹配
    /// </summary>
    public bool VerifyPassword(string password, string hashedPassword)
    {
      if (string.IsNullOrWhiteSpace(password))
        return false;

      if (string.IsNullOrWhiteSpace(hashedPassword))
        return false;

      try
      {
        // 使用BCrypt验证密码
        return BCrypt.Net.BCrypt.Verify(password, hashedPassword);
      }
      catch (Exception)
      {
        // 哈希值格式错误或验证过程中出现异常
        return false;
      }
    }

    /// <summary>
    /// 检查密码强度
    /// </summary>
    public PasswordStrength CheckPasswordStrength(string password)
    {
      if (string.IsNullOrWhiteSpace(password))
        return PasswordStrength.TooWeak;

      if (password.Length < 6)
        return PasswordStrength.TooWeak;

      var score = 0;

      // 长度评分
      if (password.Length >= 8) score++;
      if (password.Length >= 12) score++;
      if (password.Length >= 16) score++;

      // 字符种类评分
      if (Regex.IsMatch(password, "[a-z]")) score++; // 小写字母
      if (Regex.IsMatch(password, "[A-Z]")) score++; // 大写字母  
      if (Regex.IsMatch(password, "[0-9]")) score++; // 数字
      if (Regex.IsMatch(password, "[^a-zA-Z0-9]")) score++; // 特殊字符

      return score switch
      {
        <= 2 => PasswordStrength.Weak,
        3 or 4 => PasswordStrength.Medium,
        5 => PasswordStrength.Strong,
        >= 6 => PasswordStrength.VeryStrong
      };
    }
  }
}